/**
* SEFileNavigator.java
*
* This program is distributed under the terms of the GNU General Public
* License
* Copyright 2008 NJ Pearman
*
* This file is part of MobScrob.
*
* MobScrob is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobScrob is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MobScrob. If not, see <http://www.gnu.org/licenses/>.
*/
package mobscrob.navigator;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.List;
import mobscrob.alert.AlertType;
import mobscrob.alert.Alertable;
import mobscrob.event.FileCommandListener;
import mobscrob.event.FileCommandNotifier;
import mobscrob.logging.Log;
import mobscrob.logging.LogFactory;
import mobscrob.midlet.Callback;
import mobscrob.midlet.MobScrobDisplay;
import mobscrob.playlist.Playlist;
import mobscrob.playlist.PlaylistFullException;
import mobscrob.playlist.Playlist.PlaylistFile;
/**
* A Sony Ericsson implementation of a File Navigator
*
* @author Neill
*
*/
public class SEFileNavigator implements MobScrobDisplay, CommandListener,
FileCommandNotifier {
private static final Log log = LogFactory.getLogger(SEFileNavigator.class);
/** The root of this file system **/
private DirectoryNode root;
/** The current node being viewed **/
private DirectoryNode currNode;
private List currList;
private Vector currItems;
private Display parent;
private Command backCmd = new Command("Back", Command.EXIT, 1);
private Command addToPlaylistCmd = new Command("Add", Command.ITEM, 1);
private Command replacePlaylistCmd = new Command("Replace", Command.ITEM, 1);
private Command returnToMainCmd = new Command("Main", Command.ITEM, 1);
private Playlist playlist;
private Vector fcListeners;
private Callback exitCB;
private Alertable alerter;
public SEFileNavigator(Callback exitCB, Alertable alerter) {
this.root = new SystemRootNode(new DirectoryNodeManager() {
public DirectoryNode instance(String name, DirectoryNode parent) {
return new DirectoryNode(name, parent, this);
}
});
this.alerter = alerter;
init(exitCB);
}
private void init(Callback exitCB) {
this.exitCB = exitCB;
this.fcListeners = new Vector();
// set current node
this.currNode = this.root;
initUI(null);
this.currItems = new Vector();
}
/**
* Init the UI List components
*/
private void initUI(String[] listItems) {
if(listItems != null) {
this.currList = new List("Navigate", List.IMPLICIT, listItems, null);
} else {
this.currList = new List("Navigate", List.IMPLICIT);
}
this.currList.addCommand(backCmd);
this.currList.addCommand(addToPlaylistCmd);
this.currList.addCommand(replacePlaylistCmd);
this.currList.addCommand(returnToMainCmd);
this.currList.setCommandListener(this);
}
/**
* Associates the specified Playlist with this SEFileNavigator. If a
* Playlist has already been associated then the call to this method is
* ignored.
*
* @param playlist
*/
public void addPlaylist(Playlist playlist) {
final String methodName = "1";
if (playlist != null) {
this.playlist = playlist;
} else {
log.warn(methodName, "Can't add playlist - already have playlist");
}
}
/**
* Opens the File Navigator
*/
public void open(Display parent) {
final String methodName = "2";
log.info(methodName, "Opening SEFileNavigator");
// load only when actually being opened
composeList(currNode.getChildrenList(), currNode.getFilesList());
if (this.parent == null) {
this.parent = parent;
}
this.parent.setCurrent(currList);
}
/**
* Clears the current List and sets the contents to the supplied
* DirectoryNode and file details. Also clears the current items Vector and
* fills with the DirectoryNode and file details.
*
* @param directories
* @param files
*/
private void composeList(DirectoryNode[] directories, String[] files) {
final String methodName = "3";
this.currList.deleteAll();
this.currItems.removeAllElements();
String[] displayStrs = new String[directories.length + files.length];
log.info(methodName, "Creating new UI List, size " + displayStrs.length);
for (int i = 0; i < directories.length; i++) {
this.currItems.addElement(directories[i]);
displayStrs[i] = directories[i].name;
}
int offset = directories.length;
for (int i = 0; i < files.length; i++) {
if (files[i] == null) {
log.warn(methodName, "Null string at " + i);
}
this.currItems.addElement(files[i]);
displayStrs[offset+i] = files[i];
}
// recreating the List item is faster tan removing and adding
// the list items
initUI(displayStrs);
}
/*
* (non-Javadoc)
*
* @see
* javax.microedition.lcdui.CommandListener#commandAction(javax.microedition
* .lcdui.Command, javax.microedition.lcdui.Displayable)
*/
public void commandAction(Command command, Displayable s) {
final String methodName = "4";
log.debug(methodName, "Navigator received command " + command);
if (command == backCmd) {
log.info(methodName, "Back command pressed");
// get parent of current node
if (!currNode.isRoot()) {
updateCurrentNode(currNode.getParent());
} else {
// return to main menu..?
}
} else if (command == List.SELECT_COMMAND) {
log.info(methodName, "Select / play now command pressed");
int index = currList.getSelectedIndex();
Object selectedItem = currItems.elementAt(index);
if (selectedItem instanceof DirectoryNode) {
log.info(methodName, "Got directory node at " + index);
// open directory in list
updateCurrentNode((DirectoryNode) selectedItem);
} else if (selectedItem instanceof String) {
log.info(methodName, "Got String at " + index);
String fullPath = currNode.getAbsolutePath() + selectedItem;
// tell listeners to start playing
notifyFileCommandListeners(fullPath);
} else {
log.warn(methodName, "Got unexpected object at " + index);
}
} else if (command == addToPlaylistCmd) {
if (playlist != null) {
addPlaylistItems();
} else {
log.warn(methodName, "Ignoring command: no playlist associated with navigator");
}
} else if(command == replacePlaylistCmd) {
if (playlist != null) {
// first clear playlist, then re-populate
playlist.clearPlaylist();
addPlaylistItems();
} else {
log.warn(methodName, "Ignoring command: no playlist associated with navigator");
}
} else if (command == returnToMainCmd) {
log.info(methodName, "Returning to main menu");
exitCB.callback();
} else {
log.warn(methodName, "Unexpected command pressed");
}
}
/**
* Updates the current node and display with newNode.
*
* @param newNode
*/
public void updateCurrentNode(DirectoryNode newNode) {
currNode = newNode;
open(parent);
}
public void loadFileSystem() {
final String methodName = "5";
try {
root.loadAll();
} catch (IOException ex) {
log.error(methodName, "Unable to load file system");
}
}
private void addPlaylistItems() {
final String methodName = "6";
int index = currList.getSelectedIndex();
Object selectedItem = currItems.elementAt(index);
if (selectedItem instanceof DirectoryNode) {
try {
log.info(methodName, "Got directory node at " + index);
// open directory in list
DirectoryNode node = (DirectoryNode) selectedItem;
Vector allFiles = new Vector();
node.putAllAncestorFiles(allFiles);
// add all to playlist
Enumeration e = allFiles.elements();
PlaylistFile next;
log.info(methodName, "Have " + allFiles.size() + " to add to playlist");
while (e.hasMoreElements()) {
next = (PlaylistFile) e.nextElement();
if (next != null) {
try { playlist.addToPlaylist(next); }
catch(PlaylistFullException pfe) { break; }
}
}
} catch (IOException ex) {
log.error(methodName, "Unable to add directory node contents to playlist: " + ex.getMessage(), ex);
}
} else if (selectedItem instanceof String) {
log.info(methodName, "Got String at " + index);
String fullPath = currNode.getAbsolutePath() + selectedItem;
// add file to playlist
PlaylistFile file = new PlaylistFile((String) selectedItem, fullPath);
try {
playlist.addToPlaylist(file);
log.info(methodName, "Added file " + file.getLocation()
+ " to playlist");
} catch(PlaylistFullException e) {
alerter.alert(AlertType.ERROR, "Playlist full - remove tracks first!");
}
} else {
log.warn(methodName, "Got unexpected object at " + index);
}
}
/**
* @param filename
*/
private void notifyFileCommandListeners(String filename) {
Enumeration e = fcListeners.elements();
while (e.hasMoreElements()) {
((FileCommandListener) e.nextElement()).perform(FileCommandListener.SELECT, filename);
}
}
/**
* Adds listener to the list of FileListeners in this FileNavigator
*
* @param listener
*/
public void addFileListener(FileCommandListener listener) {
fcListeners.addElement(listener);
}
}